import { instantiate, Node, Prefab, sp, SpriteFrame } from "cc";
import { app } from "../App";
import { injectable, InjectableObject } from "../inject";
import UIDelegateComp from "./component/UIDelegateComp";
import { ViewParams } from "./ViewDefine";

@injectable("UIFactory")
export class UIFactory extends InjectableObject {

    createUI(prefabOrPath: string | Prefab): Promise<Node> {
        return new Promise((resolve) => {
            if (prefabOrPath instanceof Prefab) {
                let node = instantiate(prefabOrPath as Prefab);
                resolve(node);
            } else {
                let path: string = prefabOrPath;
                app.res.loadASync(path, Prefab)
                    .then((prefab) => {
                        let node = instantiate(prefab);
                        resolve(node);
                    })
                    .catch((reason) => {
                        resolve(null);
                    });
            }
        });
    }

    createView(prefabOrPath: Prefab | string, parent?: Node, args?: any): Promise<Node> {
        return new Promise(async (resolve) => {
            if (prefabOrPath instanceof Prefab) {
                let prefab: Prefab = prefabOrPath;
                let node: Node = instantiate(prefab);
                node.parent = parent;
                this.addDelegate(node, args);
                resolve(node);
            } else {
                app.res.loadASync(prefabOrPath, Prefab).then((prefab) => {
                    let node: Node = instantiate(prefab);
                    node.parent = parent;
                    this.addDelegate(node, args);
                    resolve(node);
                })
            }
        })
    }

    addDelegate(node: Node, args?: any) {
        let delegateComp: UIDelegateComp = node.addComponent(UIDelegateComp);
        delegateComp.viewParams = new ViewParams();
        delegateComp.viewParams.payload = args;
        delegateComp.add();
    }

    public createSpriteFrame(path: string): Promise<SpriteFrame> {
        return new Promise((resolve) => {
            app.res.loadASync(path + '/spriteFrame', SpriteFrame).then(res => {
                resolve(res);
            })
        })
    }

    public createSpineNode(skeFile: string) {
        return new Promise((resolve) => {
            app.res.loadASync(skeFile, sp.SkeletonData).then(skeletonData => {
                let spineNode = new Node();
                let skeleton = spineNode.addComponent(sp.Skeleton);

                skeleton.skeletonData = skeletonData;

                resolve(spineNode);
            })
        })
    }
}